package com.societyGames.interceptExercises
{
import com.societyGames.action.ActionQueue;
import com.societyGames.action.DelayAction;

import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.text.TextLineMetrics;

public class InterceptRender extends Sprite
{
  private var _numberExpression:INumberExpression;
  private var _interceptSimulation:InterceptSimulation;
  private var _mainSprite:Sprite = new Sprite();
  private var _gridSprite:Sprite = new Sprite();
  private var _lineSprite:Sprite = new Sprite();
  private var _hookDisplayObject:DisplayObject;
  private var _fishDisplayObject:DisplayObject;
  private var _boatDisplayObject:DisplayObject;
  private var _dotsSprite:Sprite = new Sprite();
  private var _actionQueue:ActionQueue;
  private var _numberWidth:int = 0;
  private var _numberHeight:int = 0;

  private const _displayUnitsPerSimulationUnit:Number = 50;
  private const _hookMoveDuration:Number = 1;
  private const _millisecondsDelayAfterHook:Number = 1000;

  private var _expressionTextField:TextField;

  [Embed(source="../../../../../InterceptExercise/assets/Background.png")]
  private static const _backgroundImageClass:Class;

  [Embed(source="../../../../../InterceptExercise/assets/Fish.png")]
  private static const _fishImageClass:Class;

  [Embed(source="../../../../../InterceptExercise/assets/Hook.png")]
  private static const _hookImageClass:Class;

  [Embed(source="../../../../../InterceptExercise/assets/Boat.png")]
  private static const _boatImageClass:Class;

  [Embed(source="../../../../../InterceptExercise/assets/Dot.png")]
  private static const _dotImageClass:Class;

  public function InterceptRender(interceptSimulation:InterceptSimulation, actionQueue:ActionQueue)
  {
    this._interceptSimulation = interceptSimulation;
    this._actionQueue = actionQueue;

    this._mainSprite.addChild(new _backgroundImageClass());

    drawGridOn(_gridSprite, _interceptSimulation.gridWidth, _interceptSimulation.gridHeight,
            _displayUnitsPerSimulationUnit, _displayUnitsPerSimulationUnit);
    this._mainSprite.addChild(_gridSprite);

    addNumbers();

    this._mainSprite.addChild(_dotsSprite);

    this._boatDisplayObject = createAlignedDisplayObject(_boatImageClass, -1, -0.7);
    this._mainSprite.addChild(_boatDisplayObject);

    this._fishDisplayObject = createAlignedDisplayObject(_fishImageClass, -1, -0.5);
    this._mainSprite.addChild(_fishDisplayObject);

    this._mainSprite.addChild(_lineSprite);

    this._hookDisplayObject = createAlignedDisplayObject(_hookImageClass, -0.5, -0.5);
    this._mainSprite.addChild(_hookDisplayObject);

    this._expressionTextField = new TextField()
    this._expressionTextField.background = true;
    this._expressionTextField.backgroundColor = 0xFFFFFF;
    this._expressionTextField.border = true;
    this._expressionTextField.borderColor = 0;
    this._expressionTextField.autoSize = TextFieldAutoSize.CENTER;

    this.addChild(_mainSprite);
  }

  private function createAlignedDisplayObject(imageClass:Class, alignX:Number, alignY:Number):DisplayObject
  {
    var displayObject:DisplayObject = DisplayObject(new imageClass());
    displayObject.x = displayObject.width * alignX;
    displayObject.y = displayObject.height * alignY;

    var container:Sprite = new Sprite();
    container.addChild(displayObject);
    return container;
  }

  public function setExpression(expression:INumberExpression):void
  {
    _numberExpression = expression;

    //Set up the fish and hook positions.
    setFishPosition(x);
    setPosition(_hookDisplayObject, _interceptSimulation.boatX, 0);
    setPosition(_boatDisplayObject, _interceptSimulation.boatX, 0);

    //Show the fish's path.
    for (var gridX:int = 0; gridX < _interceptSimulation.gridWidth; gridX++)
    {
      for (var dx:Number = 0; dx < 1.0; dx += 0.1)
      {
        var dot:DisplayObject = new _dotImageClass();
        dot.x = (gridX + dx) * _displayUnitsPerSimulationUnit;
        dot.y = this._interceptSimulation.calculateFishSimulationY(gridX + dx) * _displayUnitsPerSimulationUnit;
        this._dotsSprite.addChild(dot);
      }
    }
  }

  public function setExpressionText(text:String):void
  {
    this._expressionTextField.text = "depth = " + text;
    this._expressionTextField.x = (this._gridSprite.width / 2) - (this._expressionTextField.width / 2);
    this._expressionTextField.y = this._gridSprite.height - this._expressionTextField.height;
    this._gridSprite.addChild(this._expressionTextField);
  }

  public function setHookDepth(depth:Number):void
  {
    this._actionQueue.add(new MoveToWithLineAction(_hookDisplayObject, _hookDisplayObject.x, toDisplayY(depth), _hookMoveDuration,
            _lineSprite, _boatDisplayObject.x, _boatDisplayObject.y));
  }

  public function setFishPosition(simulationX:Number):void
  {
    setPosition(_fishDisplayObject, simulationX, this._interceptSimulation.calculateFishSimulationY(simulationX));
  }

  private function setPosition(displayObject:DisplayObject, simulationX:Number, simulationY:Number):void
  {
    displayObject.x = toDisplayX(simulationX);
    displayObject.y = toDisplayY(simulationY);
  }

  private function toDisplayX(simulationX:Number):Number
  {
    return simulationX * _displayUnitsPerSimulationUnit;
  }

  private function toDisplayY(simulationY:Number):Number
  {
    return simulationY * _displayUnitsPerSimulationUnit;
  }

  private function drawGridOn(sprite:Sprite, gridWidth:int, gridHeight:int, spaceWidth:Number, spaceHeight:Number):void
  {
    var graphics:Graphics = sprite.graphics;
    var gridWidth:int = gridWidth;
    var gridHeight:int = gridHeight;

    graphics.lineStyle(1);
    //Draw vertical lines
    for (var gridX:int = 0; gridX <= gridWidth; gridX++)
    {
      graphics.moveTo(gridX * spaceWidth, 0);
      graphics.lineTo(gridX * spaceWidth, gridHeight * spaceHeight);
    }
    //Draw horizontal lines
    for (var gridY:int = 0; gridY <= gridHeight; gridY++)
    {
      graphics.moveTo(0, gridY * spaceHeight);
      graphics.lineTo(gridWidth * spaceWidth, gridY * spaceHeight);
    }
  }

  public function showFishSwim(isCaught:Boolean):void
  {
    var stopX:Number = isCaught ? _interceptSimulation.boatX : _interceptSimulation.gridWidth;
    this._actionQueue.add(new FishSwimAction(this, this._numberExpression, stopX)); //TODO: Make the end of screen or boatX if it hits.
    if (isCaught)
    {
      this._actionQueue.add(new DelayAction(_millisecondsDelayAfterHook));
    }
  }

  public function addNumbers():void
  {
    var gridWidth:int = this._interceptSimulation.gridWidth;
    var gridHeight:int = this._interceptSimulation.gridHeight;
    var textField:TextField;
    //Calculate a sample first
    textField = createNumberTextField(0);
    //Grab values if we had a text field.
    this._numberWidth = textField.width;
    this._numberHeight = textField.height;
    //Draw x axis numbers
    var xPosition:Number = 0;
    for (var gridX:int = 0; gridX <= gridWidth; gridX++)
    {
      textField = createNumberTextField(gridX);
      textField.x = xPosition + (textField.width * 0.5);
      textField.y = 0;
      this.addChild(textField);
      xPosition += this._displayUnitsPerSimulationUnit;
    }
    //Draw y axis numbers
    var yPosition:Number = 0;
    for (var gridY:int = 0; gridY <= gridHeight; gridY++)
    {
      textField = createNumberTextField(gridY);
      textField.x = 0;
      textField.y = int(yPosition + (textField.height * 0.5));
      this.addChild(textField);
      yPosition += this._displayUnitsPerSimulationUnit;
    }
    this._mainSprite.x = this._numberWidth;
    this._mainSprite.y = this._numberHeight;
  }

  private function createNumberTextField(value:int):TextField
  {
    var textField:TextField = new TextField();
    textField.text = value.toString();
    var textFormat:TextFormat = textField.getTextFormat();
    textFormat.align = TextFormatAlign.CENTER;
    textField.setTextFormat(textFormat);
    var metrics:TextLineMetrics = textField.getLineMetrics(0);
    textField.width = metrics.width + 4;
    textField.height = metrics.height + 4;

    return textField;
  }

}
}